package com.zktravel.util;

import java.io.File;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import com.odianyun.util.io.Closer;

/**
 * 
 * @author bo.wu
 * @CreateDate 2014年7月24日
 */
public class ClassSearcher {

	private boolean allowSearchJar = false;

	public ClassSearcher() {

	}

	/**
	 * <h3>添加一个是否允许搜索Jar文件的开关</h3> <b>注意：搜索Jar将消耗更多的资源，搜索速度可能有较大的下降</b> 默认不搜索Jar
	 * 
	 * @param allowSearchJar
	 */
	public ClassSearcher(boolean allowSearchJar) {
		this.allowSearchJar = allowSearchJar;
	}

	/**
	 * 根据不含包的类名和父类型得到类对象
	 * 
	 * @param simpleName
	 * @param superType
	 * @return
	 */
	public Class<?> search(String simpleName, Class<?>... superType) {
		String classPath = System.getProperty("java.class.path");

		String[] cps = classPath.split(";");
		for (String cp : cps) {
			File file = new File(cp);
			List<String> classNames = null;
			try {
				if (file.isDirectory()) {
					classNames = searchFile(file, simpleName, file.getAbsolutePath());

				} else if (allowSearchJar) {
					classNames = searchJar(file, simpleName, file.getAbsolutePath());
				}
				if (classNames != null) {
					for (String className : classNames) {
						Class<?> clazz = Class.forName(className);
						for (Class<?> superClass : superType) {
							if (superClass.isAssignableFrom(clazz)) {
								return clazz;
							}
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		}
		return null;
	}

	private List<String> searchFile(File root, String simpleName, String rootPath) {
		List<String> classNames = new LinkedList<String>();
		File[] files = root.listFiles();
		for (File file : files) {
			if (file.isDirectory()) {
				classNames.addAll(searchFile(file, simpleName, rootPath));
			} else {
				if (file.getName().endsWith(".class")) {
					String className = getClassName(file, simpleName, rootPath);
					if (className != null) {
						classNames.add(className);
					}
				}
			}
		}
		return classNames;
	}

	private List<String> searchJar(File jarFile, String simpleName, String rootPath) throws Exception {
		List<String> classNames = new LinkedList<String>();
		JarFile jar = null;

		try {
			jar = new JarFile(jarFile);

			Enumeration<JarEntry> entries = jar.entries();
			while (entries.hasMoreElements()) {
				JarEntry entry = entries.nextElement();
				String name = entry.getName();
				if (name.endsWith(".class")) {
					String noSuffixName = name.substring(0, name.length() - 6);
					String className = noSuffixName.replaceAll("[\\\\/]", ".");
					if (simpleName.equals(className.substring(className.lastIndexOf(".") + 1))) {
						classNames.add(className);
					}
				}
			}
			return classNames;
		} finally {
			Closer.close(jar);
		}
	}

	private String getClassName(File file, String simpleName, String rootPath) {
		String filename = file.getName();
		String noSuffixName = filename.substring(0, filename.length() - 6);
		if (simpleName.equals(noSuffixName)) {
			String packagePath = file.getAbsolutePath().replace(rootPath, "").replace(filename, "");
			if (packagePath.startsWith("\\") || packagePath.startsWith("/")) {
				packagePath = packagePath.substring(1);
			}
			String packageName = packagePath.replaceAll("[\\\\/]", ".");

			return packageName + noSuffixName;
		}
		return null;
	}
}
